跳到主要内容

按照 ECMA-262 标准规定:每一个类都有一个 prototype 属性标识类的原型对象。该属性是静态属性,它有两个作用:实现继承和分享属性。实现继承和分享属性都是原型链的组成。

一、 原型链

原型 实际上就是一个数据集合,即普通对象。继承于 Object 类,由于 JavaScript 自动创建并依附于每一个构造函数。

原型对象上定义了一些内部属性用于描述该类,其中就包含该类的基类的信息。通过该信息, JavaScript 解释引擎就可以知道该类的基类。同时基类也有相同的构成,因此 JavaScript 解释引擎就可以知道基类的基类,这就建立起了一个链条,因为描述基类信息的内部属性称为 [Prototype] ,所以,该链条也被称为原型链( prototype chain )。

__proto__prototype 属性的区别

prototype 属性是一个静态属性, __proto__ 属性则是一个实例属性。 prototype 属性表示类的原型对象, __proto__ 属性表示原型对象中定义的内部属性 [Prototype] 的值。

IE 不支持使用 __proto__ 属性,其他几个主流浏览器都支持该属性。

注意的点

  • 原型链的顶端都是 null:所有的原型链最终都将指向 null ,它是原型链的终点;
  • 每一个函数都有一个 prototype 属性:只有非箭头函数的函数才有 prototype 属性,这个属性是一个对象,当使用 new 操作符创建实例时,实例的内部会指向这个 prototype 对象;
  • 实例 [Prototype] 指向构造函数的 prototype:于上面同理;
  • 修改原型将影响所有的实例:如果原型上添加或修改了属性,那么已有的所有的和未来的实例都将受到影响;
  • 属性屏蔽:实例自身的属性如果与原型链上的某属性同名,将在访问时返回实例自身的属性。但是,原型上同名属性依旧存在,只是在该实例的使用时被屏蔽了。可以通过 delete 操作符删除这个自身的属性,从而访问原型链上的属性;
  • 新能问题:过长的原型链长度将影响性能,每一次查找都将遍历整个链;
  • 构建:使用 Object.create(null) 创建纯粹的对象,这样创建的对象没有原型(即 [prototype] 指向 null),不会继承任何 Object.prototype 上的方法,适用于纯粹字典对象的场景

二、 判定属性

使用 hasOwnPropertyin 可判断一个属性是否存在于原型链或实例自身:

    1. hasOwnProperty 仅用于检测某属性是否属于实例本身,而非原型链上的属性。该属性继承于 Object.prototype
    1. in 操作符将检测某属性是否在实例本身或是否存在与原型链

三、封装

当其他部分的代码想要执行对象的某些操作时,可以借助对象向外提供的接口完成操作,借此,对象保持了自身的内部状态不会被外部代码随意修改。对象的内部保持了私有性,而外部代码只能通过对象所提供的接口访问和修改对象的内部状态,不能直接访问和修改对象的内部状态。

保持对象内部状态的私有性、明确划分对象的公共接口和内部状态,这些特性称之为封装(encapsulation)。